#ifndef UUID_826148F77E4342FE45E12B8E89D495F8
#define UUID_826148F77E4342FE45E12B8E89D495F8

extern "C"
{
#include "ext/lib_serialize.h"
}

#include <psync5/node.hpp>
#include <queue>

struct LuaNodeEvent
{
	enum Type
	{
		Connect, Disconnect, LinkCreated
	};

	LuaNodeEvent(Type type, int linkId)
	: type(type)
	, linkId(linkId)
	{
	}

	Type type;
	int linkId;
};

/* TODO: 

	1. Need a function for creating a serialization context from a link.
	This should only work once for a given link.
	2. The serialization context should be connected to the LuaLink via
	its reader/writer. The writer should build up Sections that are queued
	in the LuaLink. The reader should request received sections.
	3. The destroy function of the reader/writer should disconnect the LuaLink
	from the serialization context. Similarily, the destructor of LuaLink
	should disconnect the serialization context from the LuaLink.
	4. When a flush is requested, the LuaLink shall flush the writer of the
	serialization context.
*/

struct LuaLink : Psync5::Link
{
	LuaLink(Psync5::Node* nodeInit, int idInit, gvl::internet_addr const& addrInit, gvl::socket sockInit)
	: Psync5::Link(nodeInit, idInit, addrInit, sockInit)
	, serialize(0)
	, next_unreceived_message(0)
	, last_message_in_section(0)
	{
	}

	~LuaLink()
	{
		if(serialize)
		{
			// Sever ties by reinitializing.
			// The reader/writer does not contain any resources
			// that need to be managed so it's safe to do this.
			bytewriter_init(&serialize->writer);
			bytereader_init(&serialize->reader);
		}
	}

	void createContext(lua_State* L);

	void flush()
	{
		if(serialize)
		{
			bytewriter_flush(&serialize->writer);
		}
	}

	void updateRecvQueue()
	{
		std::unique_ptr<Psync5::Section> next;
		
		while(next = channel().recvQueue.nextSection())
		{
			next_unreceived_message += next->messageEnds;
			recvQueue.push_back(next.release());
		}
	}
	
	// Lua serialization context associated with this
	serialize_context* serialize;
	std::unique_ptr<Psync5::SendSection> nextSection;
	gvl::list<Psync5::Section> recvQueue;
	std::unique_ptr<Psync5::Section> recvSection;
	int next_unreceived_message;
	int last_message_in_section;
};
	
struct LuaNode : Psync5::Node
{
	/*override*/ void onLinkConnected(Psync5::Link& link)
	{
		events.push(LuaNodeEvent(LuaNodeEvent::Connect, link.id));
	}

	/*override*/ void onLinkDisconnected(Psync5::Link& link)
	{
		events.push(LuaNodeEvent(LuaNodeEvent::Disconnect, link.id));
	}

	/*override*/ Psync5::Link* newLink(Psync5::Node* nodeInit, int idInit, gvl::internet_addr const& addrInit, gvl::socket sockInit)
	{
		events.push(LuaNodeEvent(LuaNodeEvent::LinkCreated, idInit));
		return new LuaLink(nodeInit, idInit, addrInit, sockInit);
	}

	std::queue<LuaNodeEvent> events;
};

#endif // UUID_826148F77E4342FE45E12B8E89D495F8
